#pragma comment(linker, "/STACK:10000000")
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <set>
#include <map>
#include <cstdio>
#include <cassert>
#include <string>
#include <cstring>
#define ldb long double
#define LL long long
#define fi first
#define se second
#define fill(a, c) memset(a, c, sizeof(a))
#define sqr(a) ((a) * (a))
#define nextLine() {int c = 0; while((c = getchar()) != 10 && c != EOF);}
#define debug(a) cerr << #a << " = " << a << " ";
#define debugl(a) cerr << #a << " = " << a << "\n";
const ldb LDINF = 9128739847123.00;
const ldb eps = 1e-9;
const int INF = 1 << 30;
const ldb pi = fabsl(atan2(0.0, -1.0));
using namespace std;


class Point
{
	public:
		ldb x, y;
		void Rotate(ldb ang)
		{
			ldb _x = x * cos(ang) - y * sin(ang);
			ldb _y = y * cos(ang) + sin(ang) * x;
			x = _x;
			y = _y;
		}
};

inline bool operator < (const Point &p1, const Point &p2)
{
	return p1.x < p2.x - eps || fabsl(p1.x - p2.x) < eps && p1.y < p2.y - eps;
}

Point operator * (const Point &p1, ldb t)
{
	Point p;
	p.x = p1.x * t;
	p.y = p1.y * t;
	return p;
}

Point operator + (const Point &p1, const Point &p2)
{
	Point p;
	p.x = p1.x + p2.x;
	p.y = p1.y + p2.y;
	return p;
}


int n;
Point p[1000][4];
vector <ldb> xs;

void Load()
{
	cin >> n;
	int i;
	for (i = 0; i < n; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			cin >> p[i][j].x >> p[i][j].y;
			p[i][j].Rotate(123);
		}
	}
}

bool OnSegment(const Point &p1, const Point &p2, const Point &p3)
{
	return (p3.x > min(p1.x, p2.x) - eps && p3.x < max(p1.x, p2.x) + eps
	&& p3.y > min(p1.y, p2.y) - eps && p3.y < max(p1.y, p2.y) + eps);
}

int Intersect(const Point &p1, const Point &p2, const Point &p3, const Point &p4, Point &P)
{
	ldb A1 = p1.y - p2.y;
	ldb B1 = p2.x - p1.x;
	ldb C1 = -(A1 * p1.x + B1 * p1.y);
	ldb A2 = p3.y - p4.y;
	ldb B2 = p4.x - p3.x;
	ldb C2 = -(A2 * p3.x + B2 * p3.y);
	if (fabs(A1 * B2 - A2 * B1) < eps) return 0;
	P.x = (-C1 * B2 + B1 * C2) / (A1 * B2 - A2 * B1);
	P.y = (-C2 * A1 + A2 * C1) / (A1 * B2 - A2 * B1);
	if (OnSegment(p1, p2, P) && OnSegment(p3, p4, P)) return 1;
	return 0;
}

class Segment
{
	public:
		Point p, v;
		int type;
		Segment(){}
		Segment(Point p1, Point p2) 
		{
			p = p1;
			v.x = p2.x - p1.x;
			v.y = p2.y - p1.y;
		}
};

ostream &operator << (ostream &oss, const Segment &s)
{
	oss << "point " << s.p.x << " " << s.p.y << " vect  " << s.v.x << " "  << s.v.y << " type " << s.type;
	return oss;
}

ldb X;
vector<Segment> all;

inline bool operator < (const Segment &s1, const Segment &s2)
{
	return s1.p + s1.v * ((X - s1.p.x) / s1.v.x) < s2.p + s2.v * ((X - s2.p.x) / s2.v.x)
	 || fabsl((s1.p + s1.v * ((X - s1.p.x) / s1.v.x)).y - (s2.p + s2.v * ((X - s2.p.x) / s2.v.x)).y) < eps && s1.type < s2.type;
}


inline bool Intersect(Segment &s1, ldb x1, ldb x2)
{
	ldb a = min(s1.p.x, s1.p.x + s1.v.x);
	ldb b = max(s1.p.x, s1.p.x + s1.v.x);
	return x1 > a - eps && x2 < b + eps;
}

inline ldb getLen(Segment &s, ldb x1, ldb x2)
{
	ldb t1 = min((x1 - s.p.x) / s.v.x, (x2 - s.p.x) / s.v.x);
	ldb t2 = max((x2 - s.p.x) / s.v.x, (x1 - s.p.x) / s.v.x);
	return (t2 - t1) * sqrt(s.v.x * s.v.x + s.v.y * s.v.y);
}



void Solve()
{
	int i, j;
	Point P;
	for (i = 0; i < n; i++)
	{
		for (j = 0; j < 3; j++)
			xs.push_back(p[i][j].x);
		for (j = i + 1; j < n; j++)
		{
			for (int l = 0; l < 3; l++)
			{
				for (int o = 0; o < 3; o++)
				{
					if (Intersect(p[i][l], p[i][(l + 1) % 3], p[j][o], p[j][(o + 1) % 3], P))
					{                      	
					//	cerr << "Find Intersection " << i << " " << j << " " << l << " " << o << "\n";
						xs.push_back(P.x);
					}
				}
			}
		}
	}
	sort(xs.begin(), xs.end());
	xs.erase(unique(xs.begin(), xs.end()), xs.end());
	Segment s[3], up, dwn;
	ldb res = 0;
	for (i = 0; i + 1 < xs.size(); i++)
	{
		all.resize(0);
		X = (xs[i + 1] + xs[i]) / 2.0;
		for (j = 0; j < n; j++)
		{
			s[0] = Segment(p[j][0], p[j][1]);
			s[1] = Segment(p[j][1], p[j][2]);
			s[2] = Segment(p[j][2], p[j][0]);
			int l;
			for (l = 0; l < 3; l++)
			{
				if (Intersect(s[l], xs[i], xs[i + 1])) break;
			}
			if (l == 3) continue;
			up = s[l];
			dwn = s[l];
			up.type = dwn.type = 0;
			for (int l = 0; l < 3; l++)
			{
				s[l].type = 0;
				if (Intersect(s[l], xs[i], xs[i + 1]))
				{
					if (up < s[l]) up = s[l];
					if (s[l] < dwn) dwn = s[l];
				}
			}
			up.type = 1;
			dwn.type = 0;
			all.push_back(up);
			all.push_back(dwn);
		}
		
		sort(all.begin(), all.end());
		int bal = 0;
	//	cerr << xs[i] << " " << xs[i + 1] << "\n";
		for (j = 0; j < all.size(); j++)
		{
		//	cerr << all[j] << "\n";
			if (all[j].type == 0)
			{
				bal++;
				if (bal == 1)
				{
					res += getLen(all[j], xs[i], xs[i + 1]);
				}
			}
			else if (all[j].type == 1)
			{
				bal--;
				if (bal == 0)
				{
					res += getLen(all[j], xs[i], xs[i + 1]);
				}
			}
		}
	//	cerr << "now res = " << res << "\n";
	}
	cout << setprecision(12) << fixed << res;
}

#define file "c"
int main()
{
	#ifndef ONLINE_JUDGE
	freopen(file".in", "rt", stdin);
	freopen(file".out", "wt", stdout);
	#endif
	Load();
	Solve();
	return 0;
}